import {
  useMemo,
  useCallback,
  forwardRef,
  useContext,
  useImperativeHandle,
  useRef,
  useState,
  useEffect
} from 'react';
import { getSearchData, getSearchTextData } from '../../../designer/service';
import { ErrorBoundary } from '@inbiz/utils';
import {message} from 'antd'
import { useRequest, useUpdateEffect } from 'ahooks';
import CategoryLeft from './categoryLeft';
import CategoryTop from './CategoryTop';
import ContentHead from '../../common/contentHead';
import ContentBody from './contentBody';
import CategoryRight from './RightPanel'
import useTemplate from '../../common/useTemplate';
import SystemGroup from '../../common/SystemGroup';
import { getDefaultParams } from '../../common/useConfigs';
import EventContext from '../../common/EventContext';
import Pagination from '@inbiz/basic/Pagination';
import DesignerShowPlugin from '../../../designer/web/ShowPlugin';
import { ShowPlugin as PreviewShowPlugin } from '../index';
import { ThemeContext } from './context';
import type { ISearchData, ISynonymWord } from '../../../designer/service';
import type { IConfigItemEngineProps } from '../index';
import type {
  ISearchEngineData,
  IConfigItem,
  ISearchResultContentRef,
} from '../../common/useConfigs';
import type { ForwardedRef } from 'react';

export type ICategorySelect = (
  key: string[],
  checked: boolean,
  level: number,
  IsWhether: boolean,
) => void;
export type { IConfigItem };

let timer: any;
function debounce(fn: Function, delay: number) {
  return function () {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn();
    }, delay)
  }
}


function SearchResultContent(
  {
    option,
    engineProps,
    searchEngineData,
    activeKey,
    RightPlugin,
    $searchKeyword
  }: {
    option: Exclude<IConfigItemEngineProps['indexIibraryConfig'], undefined>[number];
    engineProps: IConfigItemEngineProps;
    searchEngineData: ISearchEngineData;
  },
  ref: ForwardedRef<ISearchResultContentRef>,
) {
  const rightFormRef = useRef()
  const { configEvents, configEventsApi, emit, inbiz } = useContext(EventContext);
  const configRef = useRef();
  const config: any = useMemo(() => {
    // 此处index为兼容_document_, folder为1
    const index =
      option.IndexName === '_document_' ? (searchEngineData.documentType == 'folder' ? 1 : 0) : option.IndexName === 'folder' ? 1 : 0;
    if (option.configs?.[index]) {
      return {
        ...option.configs?.[index],
        IndexName: option.configs?.[index].IndexName,
        Graph: searchEngineData.Graph, //存在表示图谱功能开启
        Mark: searchEngineData.ImgMarkId || option.configs?.[index].Mark, // 存在表示是 以图搜图
        controlId: engineProps.controlId,
        IndexCode: option.IndexCode,
        searchText: option.configs?.[index].searchText || searchEngineData?.searchText
      };
    }
    return {
      ...option.configs?.[0],
      IndexName: option.configs?.[0].IndexName,
      Graph: searchEngineData.Graph, //存在表示图谱功能开启
      Mark: searchEngineData.ImgMarkId || option.configs?.[0].Mark, // 存在表示是 以图搜图
      controlId: engineProps.controlId,
      IndexCode: option.IndexCode,
      searchText: option.configs?.[0].searchText || searchEngineData?.searchText
    };
  }, [option, searchEngineData]);

  // 选中的模板的数据项
  const [selected, $selected] = useState<ISearchData['RawList']>([]);
  // 切面数据
  const [sectionList, $sectionList] = useState<ISearchData['SectionList']>([]);
  // 新需求：以图搜图需改变视图类型为“大图标视图”
  const [oldShowStyle, $oldShowStyle] = useState(config.showStyle || 'list');
  // 视图类型
  const [showStyle, $showStyle] = useState<typeof config.showStyle>(config.showStyle || 'list');
  // 选中的切面
  const [categoryData, $categoryData] = useState<{ [key in string]: string | string[] }>({});
  const [showRightPanel, $showRightPanel] = useState(true);
  const [buildInSearchParams, $buildInSearchParams] = useState({ path: '', sourceUser: '' })
  // 请求数据参数
  const [params, $params] = useState(() =>
    getDefaultParams(config, { pageNumber: Number(engineProps.pageNumber), ...searchEngineData }),
  );

  // 排序字段选中
  const [sort, $sort] = useState({ IndexFieldName: params.Sort!, order: params.Order });
  // 切面点击事件选中的层级
  const categoryLevel = useRef(-1);
  const contentRef = useRef(false);
  const belongCategoryRef = useRef({ ftype: '', folderid: '' });
  // 搜索出来的结果的全选
  const [view] = useTemplate(config.columnType === 'custom' ? config.template?.content as string : '');
  const [showImgSearch, $showImgSearch] = useState(true)
  const [showTeam, $showTeam] = useState(true)
  const [showPerson, $showPerson] = useState(true)
  // fileSearchType的值并没有1, 设置成1是为了区分筛选条件中有没有改变fileSearchType,如果改变了用改变后的值,没改变就是默认值,此时要在参数那里设为all
  const [fileSearchType, $fileSearchType] = useState('1')
  /**
   * configRef是解决档案选择全部时, 索引库没有全部请求的问题
   * 同时解决km选择一个索引库,所有索引库都请求的问题
   * 还有keyword没变,切换tab不用再请求
   */
  useEffect(() => {
    configRef.current = false
  }, [config])

  useUpdateEffect(() => {
    if (activeKey !== config.IndexName) {
      return
    }
    if (configRef.current) {
      return
    }
    categoryLevel.current = -1
    $selected([]);
    $categoryData({}); // 切面不在右侧会用到
    rightFormRef?.current?.resetFields?.(searchEngineData.parentTopFolderId)
    const defaultSort = config.sortField?.find((item) => item.enable);
    let Order = defaultSort?.sort;
    if (typeof Order === 'object') {
      //@ts-ignore
      if (typeof Order.sort === 'object') {
        Order = Order.sort.sort || 'desc';
      } else {
        Order = Order.sort || 'desc';
      }
    }
    if (defaultSort) {
      // 切面变更， 选中的排序字段更新
      $sort({ IndexFieldName: defaultSort?.IndexFieldName, order: Order });
    }

    $params(getDefaultParams(config, { pageNumber: Number(engineProps.pageNumber), ...searchEngineData }));
  }, [searchEngineData, engineProps.pageNumber, activeKey]);
  useEffect(() => {
    $params(getDefaultParams(config, {
      pageNumber: Number(engineProps.pageNumber),
      ImgMarkId: config.Mark,
      searchText: config.searchText,
      ...searchEngineData
    }))
  }, [config])
    // 自动请求接口  $params得集中一下, 太分散了
  const { data, loading, refresh } = useRequest(
    () => {
      if (activeKey !== config.IndexName) {
        return Promise.reject()
      }
      configRef.current = true;
      $selected([]);
      return configEventsApi({
        request: params.searchText ? getSearchTextData : getSearchData,
        params,
        keys: ['onSearchParams', 'onSearch', 'onSearchData'],
      });
    },
    {
      onSuccess: (data) => {
        if (data.Code ==0) {
          if (!params.searchText && params.Mark) {
            $showStyle('thumbnail')
          }
          else {
            $showStyle(oldShowStyle)
          }
          //更新切面
          // if (panelFlag) {
          //   $panelFlag(false)
          //   return;
          // }
          $sectionList((list) => {
            if (list.length === 0 || categoryLevel.current === -1) {
              // $categoryData({})
              return data.SectionList || [];
            } else {
              /**
               * 从接口中筛选出比当前level值大的
               * 从原先的数据中筛选出 <=当前level值的
               * 拼接数据
               */
              const newSectionList = data?.SectionList?.filter(
                (ele, index) => index > categoryLevel.current,
              )||[];
              const filterList = list.filter((ele, index) => index <= categoryLevel.current);
              const newList = [...filterList, ...newSectionList];
              // categoryLevel.current = -1;
              return newList;
            }
          });
        } else {
          return message.warn(data.Msg)
        }
      },
      debounceWait: 300,
      refreshDeps: [params],
    },
  );

  // 唯一key
  const uniqueKey = useMemo(() => {
    return config.uniqueField?.[0]?.IndexFieldName || '_id';
  }, [config.uniqueField]);

  const handleSelectedChange = useCallback(
    (selectedData: (typeof selected)[number], checked: boolean) => {
      $selected((list) => {
        const filterList = [];
        const newListKeys: any[] = [];
        for (let index = 0; index < list.length; index++) {
          const element = list[index];
          if (!newListKeys.includes(element.RawData[uniqueKey]) || !uniqueKey) {
            filterList.push(element);
            newListKeys.push(element.RawData[uniqueKey]);
          }
        }
        if (checked) {
          const newList = [...filterList, selectedData];
          //@ts-ignore
          emit?.('onSelect', {
            selectedData,
            selected: checked,
            selectedAll: newList,
            IndexName: config.IndexName,
          });

          return newList;
        } else {
          const newList = [...filterList];
          const index = newList.findIndex(
            (item) => item.RawData[uniqueKey] === selectedData.RawData[uniqueKey],
          );
          newList.splice(index, 1);
          //@ts-ignore
          emit?.('onSelect', {
            selectedData,
            selected: checked,
            selectedAll: newList,
            IndexName: config.IndexName,
          });

          return newList;
        }
      });
    },
    [config.IndexName],
  );

  const handleChangeShowStyle = useCallback((style: 'list' | 'thumbnail' | 'bigthumbnail') => {
    $showStyle(style);
    $oldShowStyle(style);
  }, []);

  useUpdateEffect(() => {
    $showStyle(config.showStyle || 'list');
    $oldShowStyle(config.showStyle || 'list');
  }, [config.showStyle]);

  const [categorySelected, categorySearchWhere] = useMemo(() => {
    const values = Object.values(categoryData);
    const selecteds = values.flat()
    const innercategorySearchWhere = values?.length
      ? values
        .reduce((pre, next) => {
          if (next?.length && next[0] && Array.isArray(next)) {
            if (!pre[0]) {
              pre = []
            }
            if (next.length === 1) {
              pre.push(next[0]);
            } else {
              const index = next[0].indexOf(':'),
                key = next[0].slice(0, index);
              if (next[0][index + 1] === '[') {
                pre.push(`(${next.join(' OR ')})`);
              } else {
                pre.push(
                  `${key}:(${next.map((item) => item.slice(index + 2, -1)).join(' OR ')})`,
                );
              }
            }
          }

          return pre;
        }, [])
        .join(' AND ')
      : '';
    return [selecteds, innercategorySearchWhere] as const;
  }, [categoryData]);

  const handleCategoryChange: ICategorySelect = useCallback((keys, checked, level, IsWhether) => {
    categoryLevel.current = level;
    $categoryData((selectedCategory) => {
      const newData = { ...selectedCategory };
      const keyData = 'level_' + level;
      if (checked) {
        newData[keyData] = IsWhether ? [...(newData[keyData] || []), ...keys] : keys;
        newData[keyData] = [...new Set(newData[keyData])];
      } else {
        const list = [...(newData[keyData] || [])];
        keys.forEach((key) => {
          list.splice(list.indexOf(key), 1);
        });
        newData[keyData] = list;
      }

      Object.keys(newData).forEach((key) => {
        if (Number(key.replace('level_', '')) > level) {
          delete newData[key];
        }
      });
      return newData;
    });
  }, []);

  // 判断高级搜索和所在目录以及来源用户是否有重复的字段
  const getMetaSearchArr = (obj: { path: string, sourceUser?: string }) => {
    let metaSearchWhere: string[] = []
    if (searchEngineData.SearchWhere) {
      metaSearchWhere = searchEngineData.SearchWhere.split('AND').map(item => item.trim())
    }
    // 如果有高级搜索, 则替换, 没有则push
    if (metaSearchWhere.length > 0) {
      if (obj.path) {
        const pathIndex = metaSearchWhere.findIndex(ele => ele.includes('filepath') || ele.includes('folderpath'))
        if (pathIndex > -1) {
          metaSearchWhere.splice(pathIndex, 1)
        }
        metaSearchWhere.push(obj.path)
      }
      if (obj.sourceUser) {
        // const createIndex = metaSearchWhere.findIndex(ele => ele.includes('filecreateoperator') || ele.includes('foldercreateoperator'))

        // const modifyIndex = metaSearchWhere.findIndex(ele => ele.includes('filemodifyoperator') || ele.includes('foldermodifyoperator'))

        metaSearchWhere.push(obj.sourceUser)
      }
    } else {
      if (obj.path) {
        metaSearchWhere.push(obj.path)
      }
      if (obj.sourceUser) {
        metaSearchWhere.push(obj.sourceUser)
      }
    }
    return metaSearchWhere
  }
  useUpdateEffect(() => {

    if (activeKey !== config.IndexName) {
      return
    }

    /*
      更新请求数据
      因为后端不改接口,所以本来用扩展运算符就解决的问题, 现在要写这么多
      首先,将高级搜索的条件分割成数组
      其次判断右侧属性是否存在值
      然后判断高级搜索中的条件和右侧属性的条件是否重复
      如果重复,则用右侧属性覆盖高级搜索中的条件
    */
    $params((params) => {

      const metaSearchWhere = getMetaSearchArr(buildInSearchParams)
      const SearchWhere = [config.resultsSearchCriteria, ...metaSearchWhere, categorySearchWhere]
        .filter((item) => !!item)
        .join(' AND ')
        const sessionSort = sessionStorage.getItem(`${config.IndexName}_searchSortData`)
      let newsessionSort = sort
      if (sessionSort) {
        newsessionSort = JSON.parse(sessionSort)
      }
      /**
       * fileSearchType是enterprise(企业),那么权限不变
       * fileSearchType是all(说明是重置或者清空), team,person时(不显示权限),所以权限为0
       */
      const newParams = {
        ...params,
        Order: newsessionSort.order,
        Sort: newsessionSort.IndexFieldName,
        IsSynonymSearch: searchEngineData.IsSynonymSearch,
        FuzzyFields: (config.vagueSearchField || [])?.map((item) => item.IndexFieldName).join(','),
        HighlightField: config.highlightField?.map((item) => item.IndexFieldName).join(','),
        ExcludesFields: config.excludeField?.map((item) => item.IndexFieldName).join(','),
        KeyWord: searchEngineData.KeyWord! || config.defaultSearchCriteria,
        IndexName: searchEngineData.documentType ?? config.IndexName,
        PageIndex: 1,
        fileSearchType: fileSearchType == '1' ? 'all' : fileSearchType,
        PermType: fileSearchType == 'enterprise' || fileSearchType == 'all' ? params.PermType : 0,
        IsFuzzySearch: searchEngineData.isFuzzySearch,
        Mark: searchEngineData.ImgMarkId,
        SearchWhere,
        categorySearchWhere // 右侧所在目录会用到
      }

      if (belongCategoryRef.current.folderid && belongCategoryRef.current.folderid !== '7' && !belongCategoryRef.current.ftype) {
        // 这个嵌套的有点深 这里 -> RightPanel -> buildIn -> BuildInArea -> BelongDirectory
        rightFormRef.current?.getData(newParams)
      }
      return newParams
    });
  }, [categorySearchWhere, searchEngineData, buildInSearchParams, fileSearchType]);

  const handleSortChange = useCallback(({ IndexFieldName, order }: typeof sort) => {
    if (order) {
      $sort({ IndexFieldName, order });
    } else {
      $sort({ IndexFieldName, order: undefined });
    }
    $params((params) => ({
      ...params,
      PageIndex: 1,
      Sort: order ? IndexFieldName : '',
      Order: order ? order : 'desc',
    }));
  }, []);

  // 翻页
  const handlePaginationChange = useCallback(({ current: PageIndex, pageSize: PageSize }) => {
    $params((param) => ({ ...param, PageIndex, PageSize }));
  }, []);

  // 系统分类变更
  const handleSystemGroupChange = useCallback((key) => {
    // 清空选择的切面
    $categoryData({});
    // 更新参数
    $params((params) => ({ ...params, groupNum: key, PageIndex: 1 }));
  }, []);
  useImperativeHandle(
    ref,
    () => ({
      getSelected: () => selected,
      getData: () => data?.RawList || [],
      refresh,
      clearSelected: () => {
        $selected([]);
        // $toggleAllChecked(false);
      },
      getSearchParams: () => params,
      setSearchParams: (CustomWhere) => {
        $categoryData({})
        rightFormRef?.current?.clearForm?.()
        categoryLevel.current = -1;
        $params((p) => ({ ...p, ...CustomWhere }))
      },
      setsearchKeyword: (val) => {
        $searchKeyword(val)
      },
      clearRightPanel: rightFormRef?.current?.resetFields,
      setShowImgSearch: (bool: boolean) => {
        $showImgSearch(bool)
      },
      setshowTeam: (bool: boolean) => {
        $showTeam(bool)
      },
      setshowPerson: (bool: boolean) => {
        $showPerson(bool)
      }
    }),
    [selected, data, refresh, params],
  );
  const ShowPlugin = useMemo(() => {
    return engineProps.inbiz.browser.designer ? DesignerShowPlugin : PreviewShowPlugin;
  }, []);

  const ContentMainView = useMemo(() => {
    let curentNumber = 0
    let metaKeys = []
    let panelKeys = []
    // 内置
    const buildInValue = rightFormRef?.current?.buildInForm?.getFieldsValue() || {}
    // 权限
    const permTypeValue = rightFormRef?.current?.permTypeForm?.getFieldsValue() || {}

    // 元数据
    const metaValue = rightFormRef?.current?.metaForm?.getFieldsValue() || {}

    const PermType = permTypeValue?.PermType
    for (const key in metaValue) {
      if (metaValue[key].value) {
        metaKeys.push(key)
      }
    }
    for (const key in categoryData) {
      if (categoryData[key].length > 0) {
        panelKeys.push(key)
      }
    }
    // 来源用户
    if (buildInValue?.sourceuser && buildInValue?.sourceuser.length > 0) {
      curentNumber += 1
    }
    // 所在目录
    if (buildInValue?.filepath?.value || buildInValue?.folderpath?.value) {
      curentNumber += 1
    }
    // 匹配类型
    if (buildInValue?.SearchFields && buildInValue?.SearchFields.length > 0) {
      curentNumber += 1
    }
    // 判断是否根据权限筛选,所以true跟false都要加1
    if (PermType) {
      curentNumber += 1
    }
    // 切面和元数据
    if (panelKeys.length > 0) {
      if (categoryData.status) {
        curentNumber += (panelKeys.length - 1)
      } else {
        curentNumber += panelKeys.length
      }
    }
    // 元数据
    if (metaKeys.length > 0) {
      curentNumber += metaKeys.length
    }
    if (configEvents.current?.onsetFilterNumber) {
      curentNumber = configEvents.current?.onsetFilterNumber(curentNumber)
    }

    const viewDom = (
      <>
        <ShowPlugin IndexCode={option.IndexCode} pluginName='SearchResultEngine.Plugin' />
        <ErrorBoundary>
          <ContentHead
            total={data?.Total || 0}
            sort={sort}
            controlId={engineProps.controlId}
            onSortChange={handleSortChange}
            sortField={config.sortField}
            showStyle={showStyle}
            categoryLevel={categoryLevel}
            onShowStyleClick={handleChangeShowStyle}
            config={config}
            selected={selected}
            onSelect={handleSelectedChange}
            dataSoure={data?.RawList}
            $showRightPanel={$showRightPanel}
            showRightPanel={showRightPanel}
            params={params}
            showImgSearch={showImgSearch}
            CenterPlugin={<ShowPlugin IndexCode={option.IndexCode} pluginName='SearchResultEngine.CenterPlugin' />}
            filterNumber={curentNumber}
          />
          <ContentBody
            view={view}
            config={config}
            dataSoure={data?.RawList}
            showStyle={showStyle}
            loading={loading}
            selected={selected}
            onSelect={handleSelectedChange}
            uniqueKey={uniqueKey}
            designer={engineProps.inbiz.browser.designer}
            params={params}
            $params={$params}
          />
        </ErrorBoundary>
      </>
    );
    if (config.columnType == 'list') {
      return viewDom;
    } else {
      if (view) {
        if (view.MainView) {
          const MainView = view.MainView;
          return (
            <MainView
              {...{
                data,
                sort,
                handleSortChange,
                showStyle,
                handleChangeShowStyle,
                config,
                loading,
                selected,
                handleSelectedChange,
                uniqueKey,
                inbiz,
                plugin: <ShowPlugin IndexCode={option.IndexCode} pluginName='SearchResultEngine.Plugin' />
              }}
            />
          );
        } else {
          return viewDom;
        }
      } else {
        return null;
      }
    }
  }, [
    data,
    sort,
    handleSortChange,
    showStyle,
    handleChangeShowStyle,
    config,
    loading,
    selected,
    handleSelectedChange,
    uniqueKey,
    view,
    showRightPanel,
    categoryData,
    params,
    showImgSearch
  ]);

  const getChecked = useCallback(
    (childItem) => {
      const categoryDataKeys = Object.values(categoryData).flat();
      return childItem.sectionItemList
        .map((element) => element.Key)
        .every((ele) => categoryDataKeys.includes(ele));
    },
    [categoryData],
  );
  const handlechange = (e, thelist, level, isWhether) => {
    const keys = thelist.filter((ele) => ele.Value).map((element) => element.Key);
    handleCategoryChange(keys, e.target.checked, level, isWhether);
  };

  const panelComponent = useMemo(() => {

    switch (config.sectionDisplayPosition) {
      case 'left':
        return <CategoryLeft
          list={sectionList}
          config={config}
          selected={categorySelected}
          wholeref={contentRef}
          onSelected={handleCategoryChange}
        />

      case 'right':
        return <CategoryRight
          list={sectionList}
          config={config}
          selected={categorySelected}
          onSelected={handleCategoryChange}
          $showRightPanel={$showRightPanel}
          handleSortChange={handleSortChange}
          $params={$params}
          params={params}
          engineProps={engineProps}
          searchEngineData={searchEngineData}
          $categoryData={$categoryData}
          ShowPlugin={ShowPlugin}
          IndexCode={option.IndexCode}
          RightPlugin={RightPlugin}
          categoryLevel={categoryLevel}
          showRightPanel={showRightPanel}
          ref={rightFormRef}
          showTeam={showTeam}
          showPerson={showPerson}
          $selected={$selected}
          categorySearchWhere={categorySearchWhere}
          $buildInSearchParams={$buildInSearchParams}
          $fileSearchType={$fileSearchType}
          belongCategoryRef={belongCategoryRef}
          getMetaSearchArr={getMetaSearchArr}
          buildInSearchParams={buildInSearchParams}
        />

      default:
        return <CategoryTop
          list={sectionList}
          config={config}
          selected={categorySelected}
          onSelected={handleCategoryChange}
          engineProps={engineProps}
        />
    }
  }, [config.sectionDisplayPosition, categorySearchWhere,
  config.showContents, showRightPanel, sectionList,
    categorySelected, handleCategoryChange])

  return (
    <div className="searchResultContentBox">
      <SystemGroup
        config={config}
        showSystem={config.showSystem && option.IndexName !== '_document_'}
        onChange={handleSystemGroupChange}
      />
      <div ref={contentRef} className={`searchResultContent ${config.sectionDisplayPosition}`}>
        {config.section && !!sectionList?.length && config.sectionDisplayPosition !== 'right' && (
          <div className={`category ${config.sectionDisplayPosition === 'left' ? 'leftTab' : ''}`}>
            <ThemeContext.Provider
              value={{
                getChecked,
                handlechange,
                categoryData,
              }}
            >
              {panelComponent}
            </ThemeContext.Provider>
          </div>
        )}
        <div
          className={`contentMain`}
        >
          {ContentMainView}
          {!loading && !!data?.Total && <div className="paginationBox">
            <Pagination
              onPageChange={handlePaginationChange}
              refreshData={refresh}
              pageRefresh={true}
              pagination={{
                current: params.PageIndex,
                pageSize: Number(params.PageSize),
                total: data?.Total || 0,
                showQuickJumper: true,
                showSizeChanger: true,
                defaultPageSize: Number(params.PageSize),
                defaultCurrent: 1,
                showLessItems: true,
              }}
            />
          </div>}
        </div>
        {config.section && config.sectionDisplayPosition === 'right' && <div
          className={`category ${config.sectionDisplayPosition === 'right' ? 'rightTabShowLine' : ''} ${showRightPanel ? 'rightTabShowLine' : 'rightTabNoLine'}`}
          style={{ flex: showRightPanel ? 1 : 0 }}
        >
          <ThemeContext.Provider
            value={{
              getChecked,
              handlechange,
              categoryData,
            }}
          >
            {panelComponent}
          </ThemeContext.Provider>
        </div>}
      </div>
    </div>
  );
}

export default forwardRef(SearchResultContent);
